using UnityEngine;
using System.Collections;

public class Algorithm : MonoBehaviour 
{

	// Use this for initialization
	void Start () 
	{
	
	}
	
	// Update is called once per frame
	void Update () 
	{
	
	}
	
	public class BSPNode
	{
		public double LeftEdge;
		public double RightEdge;
		public double TopEdge;
		public double BottomEdge;
			
		public double NodeWidth;
		public double NodeHeight;
			
		private Orientation SplitOrientation;
		public double SplitLocation;
			
		public BSPNode Left{get; set;}
		public BSPNode Right{get; set;}
			
		static public Random r;
		static private double SmallestPartitionSize = .15;
		static private double MaxPartitionSizeRatio = 1.5f;
		static private double HomogeneityFactor = 0.25;
			
		static public Map Map;
		
		private enum Orientation {Horizontal, Vertical};
		
		public BSPNode(double startX, double startY, double endX, double endY)
		{
			LeftEdge = startX;
			RightEdge = endX;
			TopEdge = startY;
			BottomEdge = endY;
			
			NodeWidth = RightEdge - LeftEdge;
			NodeHeigth = BottomEdge - TopEdge;
		}
		
		public void Partition()
		{
			if(NodeWidth / NodeHeight > MaxPartitionSizeRatio)
			{
				SplitOrientation = Orientation.Vertical;
			}
			else if(NodeHeight / NodeWidth > MaxPartitionSizeRatio)
			{
				SplitOrientation = Orientation.Horizontal;
			}
			else
			{
				SplitOrientation = (r.Next(2) == 1) ? Orientation.Horizontal:Orientation.Vertical;
			}
			
			if(SplitOrientation == Orientation.Horizontal)
			{
				SplitLocation = LeftEdge + HomogenizedRandomValue() * NodeWidth;
				
				Left = new BSPNode(LeftEdge, TopEdge, SplitLocation, BottomEdge);
				Right = new BSPNode(SplitLocation, TopEdge, RightEdge, BottomEdge);
				
				if(WeShouldSplit(SplitLocation - LeftEdge))
				{
					left.Partition();
				}
				if(WeShouldSplit(RightEdge - SplitLocation))
				{
					right.Partition();
				}
			}
			else
			{
				SplitLocation = TopEdge + HomogenizedRandomValue() * NodeHeight;
				
				Left = new BSPNode(LeftEdge, TopEdge, RightEdge, SplitLocation);
				Right = new BSPNode(LeftEdge, SplitLocation, RightEdge, BottomEdge);
				
				if(WeShouldSplit(SplitLocation - TopEdge))
				left.Partition();
				
				if(WeShouldSplit(BottomEdge - SplitLocation))
					right.Partition();
			}
		}
			
		private bool WeShouldSplit(double partitionSize)
		{
			if(partitionSize > SmallestPartitionSize && partitionSize < SmallestPartitionSize * 2.0 && r.NextDouble() <= .1)
				return false;
							
			return partitionSize > SmallestPartitionSize;
		}
			
		private double HomogenizedRandomValue()
		{
			return 0.5 - (r.NextDouble() * HomogeneityFactor);
		}
			
		public void EnumerateLeafNodes(AddRoomDelegate addRoomDelegate)
		{
			if(Left != null || Right != null)
			{
				if(Left != null)
				{
					Left.EnumerateLeafNodes(addRoomDelegate);
				}
				if(Right != null)
				{
					Right.EnumerateLeafNodes(addRoomDelegate);
				}
			}
			else
			{
				addRoomDelegate(LeftEdge, TopEdge, RightEdge, BottomEdge);
			}
		}
		
		public void render(Graphics gr)
		{
			float w = Map.MapWidth * 8;
			float h = Map.MapHeight * 8;
			gr.FillRectangle(Brushes.Black, (float)LeftEdge * w + 10, (float)TopEdge * h + 10, (float)(RightEdge - LeftEdge) * w, (float)(BottomEdge - TopEdge) * h);
			gr.DrawRectangle(Pens.Red, (float)LeftEdge * w + 10, (float)TopEdge * h + 10, (float)(RightEdge - LeftEdge) * w, (float)(BottomEdge - TopEdge) * h);
			
			if(Left != null)
			{
				Left.Render(gr);
			}
			if(Right != null)
			{
				Right.Render(gr);
			}
		}
	}
}
